/*
 * (C) Copyright IBM Corp. 2004, 2005
 * Copyright (c) 2005, Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307 USA.
 *
 * Author(s):
 *     Kevin Gao <kevin.gao@intel.com>
 *     Carl McAdams <carlmc@us.ibm.com>
 *     Wang jing <jing.j.wang@intel.com>
 * 
 * Spec:        HPI-B.01.01
 * Function:    saHpiSensorEventEnableSet
 * Description:   
 *   Change event enable status,
 *   see if there's an event generated
 * Line:        P88-31:P88-31
 */
#include <stdio.h>
#include <string.h>
#include "saf_test.h"
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_SENSORS 2000 
#define POLL_COUNT 10  // poll for events after every "n" sensors

static int sensorCount;

typedef struct {
    SaHpiResourceIdT resourceId;
    SaHpiSensorNumT sensorNum;
    SaHpiBoolT enabled;
    SaHpiBoolT foundEvent;
	SaHpiBoolT foundFirstEvent;
} SensorData;

static SensorData sensorData[MAX_SENSORS];

/********************************************************************************************
 * 
 * Determine if two boolean values are the same.  Keep in mind that any positive value
 * is considered to be true.
 * 
 ********************************************************************************************/

SaHpiBoolT boolean_equals(SaHpiBoolT b1, SaHpiBoolT b2)
{
    if (b1 && b2)
        return SAHPI_TRUE;

    if (!b1 && !b2)
        return SAHPI_TRUE;

    return SAHPI_FALSE;
}

/**********************************************************************************
 *
 * 
 *
 **********************************************************************************/

int verifyEvents() {
    int i;
    int retval = SAF_TEST_PASS;

    for (i = 0; i < sensorCount; i++) {
            if (!sensorData[i].foundEvent) {
                    retval = SAF_TEST_FAIL;
                    m_print("Resource %d; sensor %d did not generate generate a change event!",
                            sensorData[i].resourceId, sensorData[i].sensorNum);
            }
    }

    return retval;
}

int run_test(SaHpiSessionIdT session_id, SaHpiResourceIdT resource_id,
             SaHpiSensorNumT sensorNum, SaHpiBoolT enabled)
{
        SaErrorT val;
        int ret = SAF_TEST_UNKNOWN;

        val = saHpiSensorEventEnableSet(session_id, resource_id, sensorNum, enabled);
        if (val != SA_OK) {
                e_print(saHpiSensorEventEnableSet, SA_OK, val);
                ret = SAF_TEST_UNRESOLVED;
        } else {
                ret = SAF_TEST_PASS;

                sensorData[sensorCount].resourceId = resource_id;
                sensorData[sensorCount].sensorNum = sensorNum;
                sensorData[sensorCount].enabled = enabled;
                sensorData[sensorCount].foundFirstEvent = SAHPI_FALSE;
                sensorData[sensorCount].foundEvent = SAHPI_FALSE;
                sensorCount++;
        }

        return ret;
}

/**********************************************************************************
 *
 * Check for any events that may have been mistakenly generated by the sensors.
 *
 **********************************************************************************/

int checkForEvents(SaHpiSessionIdT sessionId)
{
    int i;
    int retval = SAF_TEST_PASS;
    SaErrorT status;
    SaHpiEventT event;
    SaHpiSensorNumT sensorNum;
    SaHpiBoolT enabled;

    while (SAHPI_TRUE) {
         status = saHpiEventGet(sessionId, SAHPI_TIMEOUT_IMMEDIATE, &event, NULL, NULL, NULL);
         if (status == SA_ERR_HPI_TIMEOUT) {
              break;
         } else if (status != SA_OK) {
              retval = SAF_TEST_UNRESOLVED;
              e_print(saHpiEventGet, SA_OK, status);
              break;
         } else if (event.EventType == SAHPI_ET_SENSOR_ENABLE_CHANGE) {
              sensorNum = event.EventDataUnion.SensorEnableChangeEvent.SensorNum;
              enabled = event.EventDataUnion.SensorEnableChangeEvent.SensorEventEnable;
              for (i = 0; i < sensorCount; i++) {
                  if ((sensorData[i].resourceId == event.Source) &&
                      (sensorData[i].sensorNum == sensorNum) &&
                      (boolean_equals(sensorData[i].enabled, enabled))) {

					  if (sensorData[i].foundFirstEvent) {
                          sensorData[i].foundEvent = SAHPI_TRUE;
					  } else {
                          sensorData[i].foundFirstEvent = SAHPI_TRUE;
						  sensorData[i].enabled = !sensorData[i].enabled;
                          status = saHpiSensorEventEnableSet(sessionId,
								                             sensorData[i].resourceId, 
								                             sensorData[i].sensorNum,
								                             sensorData[i].enabled);
                          if (status != SA_OK) {
                              retval = SAF_TEST_UNRESOLVED;
                              e_print(saHpiSensorEventEnableSet, SA_OK, status);
						  }
					  }
                  }
              }
         }
    }

    return retval;
}

SaHpiBoolT canTest(SaHpiRdrT *rdr)
{
        return ((rdr->RdrType == SAHPI_SENSOR_RDR) &&
                (rdr->RdrTypeUnion.SensorRec.EventCtrl != SAHPI_SEC_READ_ONLY) && 
                (sensorCount < MAX_SENSORS));
}


int testSensor(SaHpiSessionIdT session_id, SaHpiResourceIdT resource_id, SaHpiRdrT *rdr)
{
        SaHpiBoolT enable_old;
        SaErrorT val;
        SaHpiSensorNumT num;
        int ret = SAF_TEST_NOTSUPPORT;

        num = rdr->RdrTypeUnion.SensorRec.Num;

        val = saHpiSensorEventEnableGet(session_id, resource_id,
                                        num, &enable_old);
        if (val != SA_OK) {
                e_print(saHpiSensorEventEnableGet, SA_OK, val);
                ret = SAF_TEST_UNRESOLVED;
        } else {
                ret = run_test(session_id, resource_id, num, !enable_old);
        }

        if (ret == SAF_TEST_PASS && sensorCount % POLL_COUNT == 0) {
            ret = checkForEvents(session_id);
        }

        return ret;
}

/**********************************************************************************
 *
 * Test a resource.
 *
 **********************************************************************************/

int testResource(SaHpiSessionIdT sessionId, SaHpiResourceIdT resourceId) {
     int retval = SAF_TEST_NOTSUPPORT;
     int response;
     SaErrorT error;
     SaHpiEntryIdT nextEntryId;
     SaHpiEntryIdT entryId;
     SaHpiRdrT rdr;
     SaHpiBoolT pass = SAHPI_FALSE;

     nextEntryId = SAHPI_FIRST_ENTRY;
     while (nextEntryId != SAHPI_LAST_ENTRY && retval == SAF_TEST_NOTSUPPORT) {
          entryId = nextEntryId;
          error = saHpiRdrGet(sessionId, resourceId, entryId, &nextEntryId, &rdr);
          if (error == SA_ERR_HPI_NOT_PRESENT) {
              break;
          } else if (error != SA_OK) {
              retval = SAF_TEST_UNRESOLVED;
              e_print(saHpiRdrGet, SA_OK, error);
          } else {
              if (canTest(&rdr)) {
                   response = testSensor(sessionId, resourceId, &rdr);
                   if (response == SAF_TEST_PASS) {
                       pass = SAHPI_TRUE;
                   } else {
                       retval = response;
                   }
              }
          }
     }

     if (retval == SAF_TEST_NOTSUPPORT && pass) {
         retval = SAF_TEST_PASS;
     }

     return retval;
}

/**********************************************************************************
 *
 * Test a domain.
 *
 **********************************************************************************/

int TestDomain(SaHpiSessionIdT sessionId)
{
     int retval = SAF_TEST_NOTSUPPORT;
     int response;
     SaErrorT error;
     SaHpiEntryIdT nextEntryId;
     SaHpiEntryIdT entryId;
     SaHpiRptEntryT rptEntry;
     SaHpiBoolT pass = SAHPI_FALSE;

     sensorCount = 0;
     error = saHpiSubscribe(sessionId);
     if (error != SA_OK) {
         e_print(saHpiSubscribe, SA_OK, error);
         retval = SAF_TEST_UNRESOLVED;
     } else {
         nextEntryId = SAHPI_FIRST_ENTRY;
         while (nextEntryId != SAHPI_LAST_ENTRY && retval == SAF_TEST_NOTSUPPORT) {
              entryId = nextEntryId;
              error = saHpiRptEntryGet(sessionId, entryId, &nextEntryId, &rptEntry);
              if (error == SA_ERR_HPI_NOT_PRESENT) {
                  break;
              } else if (error != SA_OK) {
                  retval = SAF_TEST_UNRESOLVED;
                  e_print(saHpiRptEntryGet, SA_OK, error);
              } else if (rptEntry.ResourceCapabilities & SAHPI_CAPABILITY_SENSOR) {
                  response = testResource(sessionId, rptEntry.ResourceId);
                  if (response == SAF_TEST_PASS) {
                      pass = SAHPI_TRUE;
                  } else {
                      retval = response;
                  }
              }
         }

         if (retval == SAF_TEST_NOTSUPPORT && pass) {
             // Check for any remaining events that may have been generated.
             // We will pause for 5 seconds to give the last sensor time to
             // generate an event.

             sleep(5);
             retval = checkForEvents(sessionId);
			 if (retval == SAF_TEST_PASS) {
                 sleep(5);
                 retval = checkForEvents(sessionId);

                 if (retval == SAF_TEST_PASS) {
                         retval = verifyEvents();
                 }
			 }
         }

         error = saHpiUnsubscribe(sessionId);
         if (error != SA_OK) {
              e_print(saHpiUnsubscribe, SA_OK, error);
         }
     }

     return retval;
}

/**********************************************************************************
 *
 * Main Program 
 *
 **********************************************************************************/

int main()
{
     return process_all_domains(NULL, NULL, TestDomain);
}
